//
//  CSprite.cpp
//  ResidentEvil
//
//  Created by Nguyen Tri Chung on 1/6/15.
//
//

#include "CSprite.h"

CSprite::CSprite(string spriteType) {
    retainedActions = new Map<string, Action*>();
    this->spriteType = spriteType;
    runningAction = NULL;
}

CSprite::~CSprite() {
    Sprite::~Sprite();
    CC_SAFE_DELETE(retainedActions);
}

bool CSprite::init() {
    return Sprite::init();
}

bool CSprite::initWithFile(const string& filename) {
    return Sprite::initWithFile(filename);
}

bool CSprite::initWithSpriteFrameName(const string& spriteFrameName) {
    return Sprite::initWithSpriteFrameName(spriteFrameName);
}

void CSprite::initWithIdentifier(const string& identifier) {
    string frameName = identifier + BIND_CONSTANT_SUFFIX;
    if (!initWithSpriteFrameName(frameName)) {
        assert(NULL);
    }
}

Action* CSprite::createFrameCaheAction(string& pattern, int count, float duration, bool loop) {
    SpriteFrameCache* spriteFrameCache = SpriteFrameCache::getInstance();
    Vector<SpriteFrame*>* framesVector = new Vector<SpriteFrame*>;
    char frameName[128];
    for(int i = 1; i <= count; i++){
        sprintf(frameName, pattern.c_str(), i);
        SpriteFrame* frame = spriteFrameCache->getSpriteFrameByName(frameName);
        framesVector->pushBack(frame);
    }

    float delay = duration / framesVector->size();
    Animation* animation = Animation::createWithSpriteFrames(*framesVector, delay);
    Animate* animate = Animate::create(animation);
    Action* action = NULL;
    if (loop) {
        action = RepeatForever::create(animate);
    } else {
        action = (Action*) animate;
    }
    delete framesVector;
    return action;
}

void CSprite::retainAction(Action* actionValue, string actionKey) {
    if (retainedActions->at(actionKey) != NULL) {
        assert(NULL);
    }
    retainedActions->insert(actionKey, actionValue);
}

void CSprite::bind(string pattern, float duration) {
    vector<string> values = CStringUtil::split(pattern, BIND_DELIMITER);
    if (values.size() != 2) {
        assert(NULL);
    }
    
    string plistFile = values[0];
    string identifier = values[1];
    
    std::string fullPath = FileUtils::getInstance()->fullPathForFilename(plistFile);
    ValueMap dict = FileUtils::getInstance()->getValueMapFromFile(fullPath);
    ValueMap frames = dict.at(BIND_PLIST_FRAMES_NODE).asValueMap();
    int foundTotal = 0;
    
    for (auto& frame : frames) {
        string prefix = frame.first.substr(0, frame.first.find_last_of(BIND_PATTERN_CONNECTOR));
        if (prefix == identifier) {
            foundTotal++;
        }
    }
    
    if (foundTotal == 0) {
        assert(NULL);
    }
    
    if (duration == -1) {
        duration = BIND_DEFAULT_DURATION_PER_FRAME * foundTotal;
    }
    
    
    string frameNamePattern = identifier + BIND_PATTERN_SUFFIX;
    string nameNotLoop = identifier + BIND_NOT_LOOP;
    string nameLoop = identifier + BIND_LOOP;
    
    Action* notLoopAction = createFrameCaheAction(frameNamePattern, foundTotal, duration, false);
    retainAction(notLoopAction, nameNotLoop);
    
    Action* loopAction = createFrameCaheAction(frameNamePattern, foundTotal, duration, true);
    retainAction(loopAction, nameLoop);
}

void CSprite::play(string action) {
    string nameNotLoop = action + BIND_NOT_LOOP;
    Action* selectedAction = retainedActions->at(nameNotLoop);
    
    if (runningAction != selectedAction) {
        if (runningAction != NULL) {
            stopAction(runningAction);
        }
        if (selectedAction != NULL) {
            runningAction = selectedAction;
            runAction(runningAction);
        } else {
            runningAction = NULL;
        }
    }
}

void CSprite::playLoop(string action) {
    string nameLoop = action + BIND_LOOP;
    Action* selectedAction = retainedActions->at(nameLoop);
    
    if (runningAction != selectedAction) {
        if (runningAction != NULL) {
            stopAction(runningAction);
        }
        if (selectedAction != NULL) {
            runningAction = selectedAction;
            runAction(runningAction);
        } else {
            runningAction = NULL;
        }
    }
}